#include "Basic/UnitTest.h"
#include "Basic/String.h"
#include "Regex/RegexExpression.h"
#include "Regex/RegexWriter.h"
#include "Regex/Regex.h"
#include "Regex/RegexPure.h"
#include "Regex/RegexRich.h"
#include "Collections/List.h"
#include "Collections/Linq.h"
using namespace zl;
using namespace zl::regex;
using namespace zl::collections;

void TestRegexMatchPosition(bool preferPure)
{
	Regex regex(L"/d+", preferPure);
	assert(regex.IsPureMatch() == preferPure);
	assert(regex.IsPureTest() == preferPure);
	assert(regex.TestHead(L"123abc") == true);
	assert(regex.TestHead(L"abc123abc") == false);
	assert(regex.TestHead(L"abc") == false);
	assert(regex.Test(L"123abc") == true);
	assert(regex.Test(L"abc123abc") == true);
	assert(regex.Test(L"abc") == false);

	RegexMatch::Ref match;
	RegexMatch::List matches;

	match = regex.MatchHead(L"123abc");
	assert(match);
	assert(match->Success() == true);
	assert(match->Result().Start() == 0);
	assert(match->Result().Length() == 3);
	assert(match->Result().Value() == L"123");

	match = regex.MatchHead(L"abc123abc");
	assert(!match);

	match = regex.Match(L"123abc");
	assert(match);
	assert(match->Success() == true);
	assert(match->Result().Start() == 0);
	assert(match->Result().Length() == 3);
	assert(match->Result().Value() == L"123");

	match = regex.Match(L"abc123abc");
	assert(match);
	assert(match->Success() == true);
	assert(match->Result().Start() == 3);
	assert(match->Result().Length() == 3);
	assert(match->Result().Value() == L"123");

	matches.clear();
	regex.Search(L"12abc34def56", matches);
	assert(matches.size() == 3);
	assert(matches[0]->Success() == true);
	assert(matches[0]->Result().Start() == 0);
	assert(matches[0]->Result().Length() == 2);
	assert(matches[0]->Result().Value() == L"12");
	assert(matches[1]->Success() == true);
	assert(matches[1]->Result().Start() == 5);
	assert(matches[1]->Result().Length() == 2);
	assert(matches[1]->Result().Value() == L"34");
	assert(matches[2]->Success() == true);
	assert(matches[2]->Result().Start() == 10);
	assert(matches[2]->Result().Length() == 2);
	assert(matches[2]->Result().Value() == L"56");

	matches.clear();
	regex.Split(L"12abc34def56", false, matches);
	assert(matches.size() == 2);
	assert(matches[0]->Success() == false);
	assert(matches[0]->Result().Start() == 2);
	assert(matches[0]->Result().Length() == 3);
	assert(matches[0]->Result().Value() == L"abc");
	assert(matches[1]->Success() == false);
	assert(matches[1]->Result().Start() == 7);
	assert(matches[1]->Result().Length() == 3);
	assert(matches[1]->Result().Value() == L"def");

	matches.clear();
	regex.Split(L"12abc34def56", true, matches);
	assert(matches.size() == 4);
	assert(matches[0]->Success() == false);
	assert(matches[0]->Result().Start() == 0);
	assert(matches[0]->Result().Length() == 0);
	assert(matches[0]->Result().Value() == L"");
	assert(matches[1]->Success() == false);
	assert(matches[1]->Result().Start() == 2);
	assert(matches[1]->Result().Length() == 3);
	assert(matches[1]->Result().Value() == L"abc");
	assert(matches[2]->Success() == false);
	assert(matches[2]->Result().Start() == 7);
	assert(matches[2]->Result().Length() == 3);
	assert(matches[2]->Result().Value() == L"def");
	assert(matches[3]->Success() == false);
	assert(matches[3]->Result().Start() == 12);
	assert(matches[3]->Result().Length() == 0);
	assert(matches[3]->Result().Value() == L"");

	matches.clear();
	regex.Cut(L"12abc34def56", false, matches);
	assert(matches.size() == 5);
	assert(matches[0]->Success() == true);
	assert(matches[0]->Result().Start() == 0);
	assert(matches[0]->Result().Length() == 2);
	assert(matches[0]->Result().Value() == L"12");
	assert(matches[1]->Success() == false);
	assert(matches[1]->Result().Start() == 2);
	assert(matches[1]->Result().Length() == 3);
	assert(matches[1]->Result().Value() == L"abc");
	assert(matches[2]->Success() == true);
	assert(matches[2]->Result().Start() == 5);
	assert(matches[2]->Result().Length() == 2);
	assert(matches[2]->Result().Value() == L"34");
	assert(matches[3]->Success() == false);
	assert(matches[3]->Result().Start() == 7);
	assert(matches[3]->Result().Length() == 3);
	assert(matches[3]->Result().Value() == L"def");
	assert(matches[4]->Success() == true);
	assert(matches[4]->Result().Start() == 10);
	assert(matches[4]->Result().Length() == 2);
	assert(matches[4]->Result().Value() == L"56");

	matches.clear();
	regex.Cut(L"12abc34def56", true, matches);
	assert(matches.size() == 7);
	assert(matches[0]->Success() == false);
	assert(matches[0]->Result().Start() == 0);
	assert(matches[0]->Result().Length() == 0);
	assert(matches[0]->Result().Value() == L"");
	assert(matches[1]->Success() == true);
	assert(matches[1]->Result().Start() == 0);
	assert(matches[1]->Result().Length() == 2);
	assert(matches[1]->Result().Value() == L"12");
	assert(matches[2]->Success() == false);
	assert(matches[2]->Result().Start() == 2);
	assert(matches[2]->Result().Length() == 3);
	assert(matches[2]->Result().Value() == L"abc");
	assert(matches[3]->Success() == true);
	assert(matches[3]->Result().Start() == 5);
	assert(matches[3]->Result().Length() == 2);
	assert(matches[3]->Result().Value() == L"34");
	assert(matches[4]->Success() == false);
	assert(matches[4]->Result().Start() == 7);
	assert(matches[4]->Result().Length() == 3);
	assert(matches[4]->Result().Value() == L"def");
	assert(matches[5]->Success() == true);
	assert(matches[5]->Result().Start() == 10);
	assert(matches[5]->Result().Length() == 2);
	assert(matches[5]->Result().Value() == L"56");
	assert(matches[6]->Success() == false);
	assert(matches[6]->Result().Start() == 12);
	assert(matches[6]->Result().Length() == 0);
	assert(matches[6]->Result().Value() == L"");

	matches.clear();
	regex.Cut(L"XY12abc34def56ZW", true, matches);
	assert(matches.size() == 7);
	assert(matches[0]->Success() == false);
	assert(matches[0]->Result().Start() == 0);
	assert(matches[0]->Result().Length() == 2);
	assert(matches[0]->Result().Value() == L"XY");
	assert(matches[1]->Success() == true);
	assert(matches[1]->Result().Start() == 2);
	assert(matches[1]->Result().Length() == 2);
	assert(matches[1]->Result().Value() == L"12");
	assert(matches[2]->Success() == false);
	assert(matches[2]->Result().Start() == 4);
	assert(matches[2]->Result().Length() == 3);
	assert(matches[2]->Result().Value() == L"abc");
	assert(matches[3]->Success() == true);
	assert(matches[3]->Result().Start() == 7);
	assert(matches[3]->Result().Length() == 2);
	assert(matches[3]->Result().Value() == L"34");
	assert(matches[4]->Success() == false);
	assert(matches[4]->Result().Start() == 9);
	assert(matches[4]->Result().Length() == 3);
	assert(matches[4]->Result().Value() == L"def");
	assert(matches[5]->Success() == true);
	assert(matches[5]->Result().Start() == 12);
	assert(matches[5]->Result().Length() == 2);
	assert(matches[5]->Result().Value() == L"56");
	assert(matches[6]->Success() == false);
	assert(matches[6]->Result().Start() == 14);
	assert(matches[6]->Result().Length() == 2);
	assert(matches[6]->Result().Value() == L"ZW");
}

TEST_CASE(TestRegexMatchPosition)
{
	TestRegexMatchPosition(true);
	TestRegexMatchPosition(false);
}

TEST_CASE(TestRegexCapture)
{
	{
		Regex regex(L"^(<a>/w+?)(<b>/w+?)((<$a>)(<$b>))+(<$a>)/w{6}$", true);
		assert(regex.IsPureMatch() == false);
		assert(regex.IsPureTest() == false);

		RegexMatch::Ref match = regex.Match(L"vczhgeniusvczhgeniusvczhgeniusvczhgenius");
		assert(match);
		assert(match->Success() == true);
		assert(match->Result().Start() == 0);
		assert(match->Result().Length() == 40);
		assert(match->Result().Value() == L"vczhgeniusvczhgeniusvczhgeniusvczhgenius");
		assert(match->Groups().keys().size() == 2);
		assert(match->Groups().keys()[0] == L"a");
		assert(match->Groups().keys()[1] == L"b");
		assert(match->Groups()[L"a"].size() == 1);
		assert(match->Groups()[L"a"].get(0).Start() == 0);
		assert(match->Groups()[L"a"].get(0).Length() == 4);
		assert(match->Groups()[L"a"].get(0).Value() == L"vczh");
		assert(match->Groups()[L"b"].size() == 1);
		assert(match->Groups()[L"b"].get(0).Start() == 4);
		assert(match->Groups()[L"b"].get(0).Length() == 6);
		assert(match->Groups()[L"b"].get(0).Value() == L"genius");
	}
	{
	Regex regex(L"(<pattern>61(/w+)7A)");
	RegexMatch::Ref match = regex.Match(L"61A7A");
	assert(match);
	assert(match->Success() == true);
    }
	{
		Regex regex(L"^(?/d+).(?/d+).(?/d+).(<$0>).(<$1>).(<$2>)$");
		RegexMatch::Ref match;

		match = regex.MatchHead(L"12.34.56.12.56.34");
		assert(!match);

		match = regex.MatchHead(L"123.4.56.123.4.56");
		assert(match);
		assert(match->Success() == true);
		assert(match->Result().Start() == 0);
		assert(match->Result().Length() == 17);
		assert(match->Result().Value() == L"123.4.56.123.4.56");
		assert(match->Captures().size() == 3);
		assert(match->Captures().get(0).Start() == 0);
		assert(match->Captures().get(0).Length() == 3);
		assert(match->Captures().get(0).Value() == L"123");
		assert(match->Captures().get(1).Start() == 4);
		assert(match->Captures().get(1).Length() == 1);
		assert(match->Captures().get(1).Value() == L"4");
		assert(match->Captures().get(2).Start() == 6);
		assert(match->Captures().get(2).Length() == 2);
		assert(match->Captures().get(2).Value() == L"56");
	}
}

TEST_CASE(TestRegex)
{
	{
		std::wstring pattern = L"abc|ab";
		Regex regex(pattern, true);
		std::wstring str = L"efbabc";
		RegexMatch::Ref match = regex.Match(str);
		assert(match);
		assert(match->Result().Length() == 3);
	}
	{
	    std::wstring pattern = L"[ |\n]+|[\r\n]+";
	    Regex regex(pattern, true);
	    std::wstring str = L"\r\n";
	    RegexMatch::Ref match = regex.Match(str);
	    assert(match);
	    assert(match->Result().Length() == 2);
    }
	{
		std::wstring pattern = L"\"sip\":\"(<sip>[a-fA-F0-9]+)\", \"dip\":\"(<dip>[a-fA-F0-9]+)\",\"sport\":(<sport>/d+), \"dport\":(<dport>/d+),\"apptype\":(<apptype>/d+),\"appid\":(<appid>/d+),\"upbytes\":(<upbytes>/d+),\"downbytes\":(<downbytes>/d+),\"proto\":(<proto>/d+),\"ipver\":(<ipver>/d+)";
		Regex regex(pattern);
		std::wstring str = L"{\"sip\":\"432fd53a\", \"dip\":\"b50f3cb7\",\"sport\":54686, \"dport\":20480,\"apptype\":2,\"appid\":2,\"upbytes\":0,\"downbytes\":486,\"proto\":6,\"ipver\":4,\"begintime\":1395735245,\"endtime\":1395735245}";
		RegexMatch::Ref match = regex.Match(str);
		assert(match);
		assert(match->Groups().keys()[0] == L"appid");
		assert(match->Groups()[L"sip"].get(0).Value() == L"432fd53a");
	}
}

TEST_CASE(TestRegexLexer)
{
	{
		List<std::wstring> codes;
		codes.add(L"[a-zA-Z_]/w*");
		RegexLexer lexer(codes);
		List<RegexToken> tokens;
		tokens = lexer.Parse(L"123a").ToList();
		assert(tokens.size() == 2);
		assert(tokens[0].start == 0);
		assert(tokens[0].length == 3);
		assert(tokens[0].token == -1);
		assert(tokens[0].rowStart == 0);
		assert(tokens[0].columnStart == 0);
		assert(tokens[0].rowEnd == 0);
		assert(tokens[0].columnEnd == 2);
		assert(tokens[1].start == 3);
		assert(tokens[1].length == 1);
		assert(tokens[1].token == 0);
		assert(tokens[1].rowStart == 0);
		assert(tokens[1].columnStart == 3);
		assert(tokens[1].rowEnd == 0);
		assert(tokens[1].columnEnd == 3);
	}
	{

	}
	
}
